import { Controller } from "egg";

/**
 * SSO单点登录控制器
 * 提供用户注册、登录、验证、登出等接口
 */
export default class SSOController extends Controller {
  /**
   * 用户注册接口
   * POST /api/sso/register
   *
   * 请求参数：
   * - username: 用户名（必填，3-50字符）
   * - password: 密码（必填，6-50字符）
   */
  public async register() {
    const { ctx, service } = this;
    const { username, password } = ctx.request.body;

    // 记录请求开始日志
    ctx.logger.info("[SSO-REGISTER] 注册请求开始", {
      requestId: ctx.reqId,
      ip: ctx.ip,
      userAgent: ctx.get("User-Agent"),
      username: username || "undefined",
      timestamp: new Date().toISOString()
    });

    try {
      // 1. 参数验证
      if (!username || !password) {
        ctx.logger.warn("[SSO-REGISTER] 参数验证失败：缺少必填参数", {
          requestId: ctx.reqId,
          ip: ctx.ip,
          username: username || "undefined",
          hasPassword: !!password
        });

        ctx.status = 400;
        ctx.body = {
          success: false,
          message: "用户名和密码都是必填项",
          code: "MISSING_PARAMS"
        };
        return;
      }

      // 2. 参数格式验证
      if (username.length < 3 || username.length > 50) {
        ctx.logger.warn("[SSO-REGISTER] 参数验证失败：用户名长度不符合要求", {
          requestId: ctx.reqId,
          ip: ctx.ip,
          username,
          usernameLength: username.length
        });

        ctx.status = 400;
        ctx.body = {
          success: false,
          message: "用户名长度应在3-50个字符之间",
          code: "INVALID_USERNAME_LENGTH"
        };
        return;
      }

      if (password.length < 6 || password.length > 50) {
        ctx.logger.warn("[SSO-REGISTER] 参数验证失败：密码长度不符合要求", {
          requestId: ctx.reqId,
          ip: ctx.ip,
          username,
          passwordLength: password.length
        });

        ctx.status = 400;
        ctx.body = {
          success: false,
          message: "密码长度应在6-50个字符之间",
          code: "INVALID_PASSWORD_LENGTH"
        };
        return;
      }

      // 3. 调用用户服务进行注册（使用Sequelize服务）
      const result = await service.userSequelize.register(username.trim(), password);

      // 4. 根据结果返回响应
      if (result.success) {
        ctx.logger.info("[SSO-REGISTER] 注册成功", {
          requestId: ctx.reqId,
          ip: ctx.ip,
          username,
          userId: result.data?.userId,
          timestamp: new Date().toISOString()
        });

        ctx.status = 201; // 创建成功
        ctx.body = result;
      } else {
        ctx.logger.warn("[SSO-REGISTER] 注册失败", {
          requestId: ctx.reqId,
          ip: ctx.ip,
          username,
          errorCode: result.code,
          errorMessage: result.message
        });

        // 根据错误类型设置不同的HTTP状态码
        if (result.code === "USERNAME_EXISTS") {
          ctx.status = 409; // 冲突
        } else {
          ctx.status = 500; // 服务器错误
        }
        ctx.body = result;
      }
    } catch (error) {
      ctx.logger.error("[SSO-REGISTER] 注册接口异常", {
        requestId: ctx.reqId,
        ip: ctx.ip,
        username: username || "undefined",
        error: error instanceof Error ? error.message : String(error),
        stack: error instanceof Error ? error.stack : undefined,
        timestamp: new Date().toISOString()
      });

      ctx.status = 500;
      ctx.body = {
        success: false,
        message: "服务器内部错误，请稍后重试",
        code: "INTERNAL_ERROR"
      };
    }
  }

  /**
   * 用户登录接口
   * POST /api/sso/login
   *
   * 请求参数：
   * - username: 用户名（必填）
   * - password: 密码（必填）
   */
  public async login() {
    const { ctx, service } = this;
    const { username, password } = ctx.request.body;

    // 记录登录请求开始日志
    ctx.logger.info("[SSO-LOGIN] 登录请求开始", {
      requestId: ctx.reqId,
      ip: ctx.ip,
      userAgent: ctx.get("User-Agent"),
      username: username || "undefined",
      timestamp: new Date().toISOString()
    });

    try {
      // 1. 参数验证
      if (!username || !password) {
        ctx.logger.warn("[SSO-LOGIN] 参数验证失败：缺少必填参数", {
          requestId: ctx.reqId,
          ip: ctx.ip,
          username: username || "undefined",
          hasPassword: !!password
        });

        ctx.status = 400;
        ctx.body = {
          success: false,
          message: "用户名和密码都是必填项",
          code: "MISSING_PARAMS"
        };
        return;
      }

      // 2. 获取客户端信息
      const loginInfo = {
        ip: ctx.ip, // 客户端IP地址
        userAgent: ctx.get("User-Agent") || "Unknown", // 用户代理信息
        timestamp: new Date()
      };

      // 3. 调用用户服务进行登录验证（使用Sequelize服务）
      const result = await service.userSequelize.login(username.trim(), password, loginInfo);

      // 4. 处理登录结果
      if (result.success && result.data) {
        // 登录成功，直接设置Cookie而不依赖Egg.js Session
        const sessionId = result.data.sessionId;

        // 设置Session Cookie
        ctx.cookies.set("SSO_SESSION_ID", sessionId, {
          maxAge: 24 * 60 * 60 * 1000, // 24小时
          httpOnly: true, // 防XSS攻击
          secure: false, // 开发环境设为false，生产环境应设为true
          sameSite: "lax", // 防CSRF攻击
          path: "/",
          signed: false, // 使用明文Cookie，便于Socket侧直接获取
          overwrite: true // 覆盖已存在的Cookie
        });

        // 在Egg.js Session中存储自定义SessionID和其他信息
        ctx.session.sessionId = sessionId; // 重要：设置我们的自定义SessionID
        ctx.session.userId = result.data.user.id;
        ctx.session.username = result.data.user.username;
        ctx.session.loginTime = new Date();

        ctx.logger.info("[SSO-LOGIN] 登录成功", {
          requestId: ctx.reqId,
          ip: ctx.ip,
          username,
          userId: result.data.user.id,
          sessionId: result.data.sessionId,
          timestamp: new Date().toISOString()
        });

        ctx.status = 200;
        ctx.body = {
          success: true,
          message: "登录成功",
          data: {
            user: result.data.user,
            sessionInfo: {
              sessionId: result.data.sessionId,
              expiresIn: 24 * 60 * 60 * 1000, // 24小时，毫秒
              loginTime: new Date()
            }
          }
        };
      } else {
        // 登录失败
        ctx.logger.warn("[SSO-LOGIN] 登录失败", {
          requestId: ctx.reqId,
          ip: ctx.ip,
          username,
          errorCode: result.code,
          errorMessage: result.message,
          timestamp: new Date().toISOString()
        });

        if (result.code === "INVALID_CREDENTIALS") {
          ctx.status = 401; // 未授权
        } else if (result.code === "USER_DISABLED") {
          ctx.status = 403; // 禁止访问
        } else {
          ctx.status = 500; // 服务器错误
        }
        ctx.body = result;
      }
    } catch (error) {
      ctx.logger.error("[SSO-LOGIN] 登录接口异常", {
        requestId: ctx.reqId,
        ip: ctx.ip,
        username: username || "undefined",
        error: (error as any).message,
        stack: (error as any).stack,
        timestamp: new Date().toISOString()
      });

      ctx.status = 500;
      ctx.body = {
        success: false,
        message: "服务器内部错误，请稍后重试",
        code: "INTERNAL_ERROR"
      };
    }
  }

  /**
   * 验证登录状态接口
   * GET /api/sso/validate
   *
   * 用于子系统验证用户是否已登录
   * 如果未登录或登录已过期，返回需要重新登录的响应
   */
  public async validate() {
    const { ctx, service } = this;

    // 记录验证请求开始日志
    ctx.logger.info("[SSO-VALIDATE] 验证请求开始", {
      requestId: ctx.reqId,
      ip: ctx.ip,
      userAgent: ctx.get("User-Agent"),
      timestamp: new Date().toISOString()
    });

    try {
      // 1. 尝试多种方式获取SessionID
      // 方式1：从Cookie中直接读取（绕过Egg.js签名，用于自定义SessionID）
      const cookieSessionId = ctx.cookies.get("SSO_SESSION_ID", { signed: false });
      // 方式2：从Egg.js Session中读取（经过签名验证的）
      const eggSessionId = ctx.session?.sessionId;

      ctx.logger.info("[SSO-VALIDATE] 获取Session ID的多种方式", {
        requestId: ctx.reqId,
        ip: ctx.ip,
        cookieSessionId: cookieSessionId || "undefined",
        eggSessionId: eggSessionId || "undefined",
        hasSession: !!ctx.session,
        timestamp: new Date().toISOString()
      });

      // 3. 优先使用Egg.js验证过的SessionID，如果没有则尝试Cookie中的
      let sessionId = eggSessionId;
      if (!sessionId && cookieSessionId) {
        // 如果Egg.js Session中没有，但Cookie中有，说明可能是直接传入的SessionID
        sessionId = cookieSessionId;
        ctx.logger.info("[SSO-VALIDATE] 使用Cookie中的SessionID", {
          requestId: ctx.reqId,
          sessionId: sessionId,
          timestamp: new Date().toISOString()
        });
      }

      if (!sessionId) {
        ctx.logger.warn("[SSO-VALIDATE] 验证失败：未找到任何Session ID", {
          requestId: ctx.reqId,
          ip: ctx.ip,
          timestamp: new Date().toISOString()
        });

        // 单测期望 401
        ctx.status = 401;
        ctx.body = {
          success: false,
          message: "未登录，请先登录",
          code: "NOT_LOGGED_IN",
          redirectUrl: "http://localhost:5174/" // 前端可根据此字段跳转到登录页
        };
        return;
      }

      // 使用获取到的SessionID进行验证

      // 2. 验证Session有效性（使用Sequelize服务）
      const result = await service.userSequelize.validateSession(sessionId);

      // 3. 处理验证结果
      if (result.success && result.data) {
        // 验证成功，更新Session信息
        ctx.session.userId = result.data.user.id;
        ctx.session.username = result.data.user.username;
        ctx.session.lastValidateTime = new Date();

        ctx.status = 200;
        ctx.body = {
          success: true,
          message: "登录状态有效",
          data: {
            user: result.data.user,
            sessionInfo: {
              sessionId: result.data.sessionId,
              lastValidateTime: new Date(),
              isValid: true
            }
          }
        };
      } else {
        // 验证失败，清除Session
        ctx.session = null;

        if (result.code === "SESSION_EXPIRED") {
          ctx.status = 401;
        } else if (result.code === "USER_INVALID") {
          ctx.status = 403;
        } else {
          ctx.status = 401;
        }

        ctx.body = {
          ...result,
          redirectUrl: "/login" // 前端可根据此字段跳转到登录页
        };
      }
    } catch (error) {
      const cookieSessionId = ctx.cookies.get("SSO_SESSION_ID", { signed: false });

      ctx.logger.error("[SSO-VALIDATE] 验证接口异常", {
        requestId: ctx.reqId,
        ip: ctx.ip,
        sessionId: cookieSessionId,
        error: error instanceof Error ? error.message : String(error),
        stack: error instanceof Error ? error.stack : undefined,
        timestamp: new Date().toISOString()
      });

      ctx.status = 500;
      ctx.body = {
        success: false,
        message: "服务器内部错误，请稍后重试",
        code: "INTERNAL_ERROR"
      };
    }
  }

  /**
   * 用户登出接口
   * POST /api/sso/logout
   *
   * 清除用户Session和Cookie
   */
  public async logout() {
    const { ctx, service } = this;

    // 记录登出请求开始日志
    ctx.logger.info("[SSO-LOGOUT] 登出请求开始", {
      requestId: ctx.reqId,
      ip: ctx.ip,
      userAgent: ctx.get("User-Agent"),
      sessionId: ctx.session?.sessionId,
      username: ctx.session?.username,
      timestamp: new Date().toISOString()
    });

    try {
      // 1. 获取Cookie中的SessionID
      const cookieSessionId = ctx.cookies.get("SSO_SESSION_ID", { signed: false });

      if (cookieSessionId) {
        // 2. 调用用户服务进行登出处理（使用Sequelize服务）
        await service.userSequelize.logout(cookieSessionId);
      }

      // 3. 清除Cookie和Session
      ctx.cookies.set("SSO_SESSION_ID", "", {
        maxAge: 0, // 立即过期
        httpOnly: true,
        secure: false,
        sameSite: "lax",
        path: "/",
        overwrite: true
      });
      ctx.session = null;

      ctx.logger.info("[SSO-LOGOUT] 登出成功", {
        requestId: ctx.reqId,
        ip: ctx.ip,
        sessionId: cookieSessionId,
        timestamp: new Date().toISOString()
      });

      // 4. 返回登出成功响应
      ctx.status = 200;
      ctx.body = {
        success: true,
        message: "登出成功",
        data: {
          logoutTime: new Date()
        }
      };
    } catch (error) {
      const cookieSessionId = ctx.cookies.get("SSO_SESSION_ID", { signed: false });

      ctx.logger.error("[SSO-LOGOUT] 登出接口异常", {
        requestId: ctx.reqId,
        ip: ctx.ip,
        sessionId: cookieSessionId,
        error: error instanceof Error ? error.message : String(error),
        stack: error instanceof Error ? error.stack : undefined,
        timestamp: new Date().toISOString()
      });

      // 即使出现错误，也要清除Cookie和Session
      ctx.cookies.set("SSO_SESSION_ID", "", {
        maxAge: 0,
        httpOnly: true,
        secure: false,
        sameSite: "lax",
        path: "/",
        overwrite: true
      });
      ctx.session = null;

      ctx.status = 200; // 登出操作对用户来说总是成功的
      ctx.body = {
        success: true,
        message: "登出成功",
        data: {
          logoutTime: new Date()
        }
      };
    }
  }

  /**
   * 获取当前用户信息接口
   * GET /api/sso/userinfo
   *
   * 返回当前登录用户的基本信息
   */
  public async getUserInfo() {
    const { ctx, service } = this;

    // 记录获取用户信息请求开始日志
    ctx.logger.info("[SSO-USERINFO] 获取用户信息请求开始", {
      requestId: ctx.reqId,
      ip: ctx.ip,
      userAgent: ctx.get("User-Agent"),
      sessionId: ctx.session?.sessionId,
      timestamp: new Date().toISOString()
    });

    try {
      // 1. 验证登录状态 - 从Cookie获取SessionID
      const cookieSessionId = ctx.cookies.get("SSO_SESSION_ID");

      if (!cookieSessionId) {
        ctx.logger.warn("[SSO-USERINFO] 获取用户信息失败：未找到Cookie Session ID", {
          requestId: ctx.reqId,
          ip: ctx.ip,
          timestamp: new Date().toISOString()
        });

        ctx.status = 401;
        ctx.body = {
          success: false,
          message: "未登录，请先登录",
          code: "NOT_LOGGED_IN"
        };
        return;
      }

      const sessionId = cookieSessionId;

      // 2. 验证Session并获取用户信息（使用Sequelize服务）
      const result = await service.userSequelize.validateSession(sessionId);

      if (result.success && result.data) {
        ctx.logger.info("[SSO-USERINFO] 获取用户信息成功", {
          requestId: ctx.reqId,
          ip: ctx.ip,
          sessionId,
          userId: result.data.user.id,
          username: result.data.user.username,
          timestamp: new Date().toISOString()
        });

        ctx.status = 200;
        ctx.body = {
          success: true,
          message: "获取用户信息成功",
          data: result.data.user
        };
      } else {
        ctx.session = null;

        ctx.logger.warn("[SSO-USERINFO] 获取用户信息失败：Session已失效", {
          requestId: ctx.reqId,
          ip: ctx.ip,
          sessionId,
          errorCode: result.code,
          errorMessage: result.message,
          timestamp: new Date().toISOString()
        });

        ctx.status = 401;
        ctx.body = {
          success: false,
          message: "登录状态已失效，请重新登录",
          code: "SESSION_INVALID"
        };
      }
    } catch (error) {
      const cookieSessionId = ctx.cookies.get("SSO_SESSION_ID");

      ctx.logger.error("[SSO-USERINFO] 获取用户信息接口异常", {
        requestId: ctx.reqId,
        ip: ctx.ip,
        sessionId: cookieSessionId,
        error: error instanceof Error ? error.message : String(error),
        stack: error instanceof Error ? error.stack : undefined,
        timestamp: new Date().toISOString()
      });

      ctx.status = 500;
      ctx.body = {
        success: false,
        message: "服务器内部错误",
        code: "INTERNAL_ERROR"
      };
    }
  }
}
